package com.seu.magicfilter.base;


import java.nio.FloatBuffer;
import java.util.List;

import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
import com.seu.magicfilter.utils.OpenGLUtils;

import android.content.Context;
import android.opengl.GLES20;


public class MagicBaseGroupFilter extends GPUImageFilter {
  private static int[] frameBuffers = null;
  private static int[] frameBufferTextures = null;
  private int frameWidth = -1;
  private int frameHeight = -1;
  protected List<GPUImageFilter> filters;

  public MagicBaseGroupFilter(List<GPUImageFilter> filters) {
    this.filters = filters;
  }

  @Override
  public void onDestroy() {
    for (GPUImageFilter filter : filters) {
      filter.destroy();
    }
    destroyFramebuffers();
  }

  @Override
  public void init(Context context) {
    for (GPUImageFilter filter : filters) {
      filter.init(context);
    }
  }

  @Override
  public void onInputSizeChanged(final int width, final int height) {
    super.onInputSizeChanged(width, height);
    int size = filters.size();
    for (int i = 0; i < size; i++) {
      filters.get(i).onInputSizeChanged(width, height);
    }
    if (frameBuffers != null && (frameWidth != width || frameHeight != height || frameBuffers.length != size - 1)) {
      destroyFramebuffers();
      frameWidth = width;
      frameHeight = height;
    }
    if (frameBuffers == null) {
      frameBuffers = new int[size - 1];
      frameBufferTextures = new int[size - 1];

      for (int i = 0; i < size - 1; i++) {
        GLES20.glGenFramebuffers(1, frameBuffers, i);

        GLES20.glGenTextures(1, frameBufferTextures, i);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferTextures[i]);
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
            GLES20.GL_TEXTURE_2D, frameBufferTextures[i], 0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
      }
    }
  }

  @Override
  public int onDrawFrame(final int textureId, final FloatBuffer cubeBuffer,
                         final FloatBuffer textureBuffer) {
    if (frameBuffers == null || frameBufferTextures == null) {
      return OpenGLUtils.NOT_INIT;
    }
    int size = filters.size();
    int previousTexture = textureId;
    for (int i = 0; i < size; i++) {
      GPUImageFilter filter = filters.get(i);
      boolean isNotLast = i < size - 1;
      if (isNotLast) {
        GLES20.glViewport(0, 0, mInputWidth, mInputHeight);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
        GLES20.glClearColor(0, 0, 0, 0);
        filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        previousTexture = frameBufferTextures[i];
      } else {
        GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);
        filter.onDrawFrame(previousTexture, cubeBuffer, textureBuffer);
      }
    }
    return OpenGLUtils.ON_DRAWN;
  }

  public int onDrawFrame(int textureId) {
    if (frameBuffers == null || frameBufferTextures == null) {
      return OpenGLUtils.NOT_INIT;
    }
    int size = filters.size();
    int previousTexture = textureId;
    for (int i = 0; i < size; i++) {
      GPUImageFilter filter = filters.get(i);
      boolean isNotLast = i < size - 1;
      if (isNotLast) {
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
        GLES20.glClearColor(0, 0, 0, 0);
        filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        previousTexture = frameBufferTextures[i];
      } else {
        filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
      }
    }
    return OpenGLUtils.ON_DRAWN;
  }

  private void destroyFramebuffers() {
    if (frameBufferTextures != null) {
      GLES20.glDeleteTextures(frameBufferTextures.length, frameBufferTextures, 0);
      frameBufferTextures = null;
    }
    if (frameBuffers != null) {
      GLES20.glDeleteFramebuffers(frameBuffers.length, frameBuffers, 0);
      frameBuffers = null;
    }
  }

  public int getSize() {
    return filters.size();
  }
}
